﻿using Admin.Common;
using Admin.Common.SqlTool;
using Admin.IRepository;
using Admin.Model.Tool;
using Dapper;
using MySql.Data.MySqlClient;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;

namespace Admin.Repository
{
    public class BaseRepository<TEntity> : Repository, IBaseRepository<TEntity> where TEntity : class, new()
    {
        private string TableName;

        public BaseRepository()
        {

            #region 获取表名
            var type = typeof(TEntity);
            var attr = type.GetCustomAttributes(typeof(MyTableAttribute), false).FirstOrDefault();
            if (attr == null) throw new Exception("请添加[MyTable(表名)]");
            var myTable = attr as MyTableAttribute;
            TableName = myTable?.TableName;
            #endregion
        }

        #region 增删改
        /// <summary>
        /// 批量删除
        /// </summary>
        /// <param name="ids">主键ids 多个逗号隔开</param>
        /// <returns>返回受影响的行数</returns>
        public async Task<int> Delete(string ids)
        {
            int res = 0;

            IDbTransaction transaction = _conn.BeginTransaction();
            try
            {
                foreach (string id in ids.Split(','))
                {
                    string sql = $"delete from {TableName} where Id=@id;";
                    res += await BaseDelete(sql, new { id }, transaction);
                }
                transaction.Commit();
            }
            catch (Exception ex)
            {
                transaction.Rollback();
            }
            return res;
        }
        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="id">主键ID</param>
        /// <returns>返回受影响的行数</returns>
        public async Task<int> Delete(int code, IDbTransaction transaction = null)
        {
            string sql = $"delete from {TableName} where Id=@Id";
            return await BaseDelete(sql, new { Id = code }, transaction);
        }
        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="param">参数实体</param>
        /// <param name="sqlWhere">where条件，参数化写法，值放param里传</param>
        /// <returns>返回受影响的行数</returns>
        public async Task<int> Delete(object param, string sqlWhere, IDbTransaction transaction = null)
        {
            if (string.IsNullOrWhiteSpace(sqlWhere))
                sqlWhere = "1=0";
            string sql = $"delete from {TableName} where {sqlWhere}";

            return await BaseDelete(sql, param, transaction);
        }
        /// <summary>
        /// 根据主键修改部分字段 
        /// </summary>
        /// <param name="model">参数实体</param>
        /// <param name="fields">修改的字段</param>
        /// <returns>返回受影响的行数</returns>
        public async Task<int> Edit(object param, string[] fields, IDbTransaction transaction = null)
        {
            string sql = $"update {TableName} set {SqlHelper.SqlSetJoin(fields)} where Id=@Id";
            return await BaseEdit(sql, param, transaction);
        }
        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="model">实体</param>
        /// <param name="fields">修改的字段</param>
        /// <param name="sqlWhere">修改的条件:参数化写法，值放param里传</param>
        /// <returns>返回受影响的行数</returns>
        public async Task<int> Edit(object param, string[] fields, string sqlWhere, IDbTransaction transaction = null)
        {
            if (string.IsNullOrEmpty(sqlWhere))
                sqlWhere = "1=0";
            string sql = $"update {TableName} set {SqlHelper.SqlSetJoin(fields)} where {sqlWhere}";

            return await BaseEdit(sql, param, transaction);
        }
        /// <summary>
        /// 新增
        /// </summary>
        /// <param name="model">参数实体</param>
        /// <param name="fields">新增的字段</param>
        /// <returns>主键ID</returns>
        public async Task<int> Insert(object param, string[] fields, IDbTransaction transaction = null)
        {
            string sql = $"insert into {TableName}({SqlHelper.SqlJoin(fields)}) values({SqlHelper.SqlValueJoin(fields)})";
            return await BaseInsert<int>(sql, param, transaction);
        }
        /// <summary>
        /// 新增
        /// </summary>
        /// <param name="model">参数实体</param>
        /// <returns>主键IDtion</returns>
        public async Task<int> Insert(TEntity model, IDbTransaction transaction = null)
        {
            string sql = $"insert into {TableName}({GetField(model)}) values({GetField(model, "@")})";
            return await BaseInsert<int>(sql, model, transaction);
        }
        /// <summary>
        /// 批量新增
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>
        public async Task<int> Insert(List<TEntity> list)
        {
            int res = 0;

            IDbTransaction transaction = _conn.BeginTransaction();
            try
            {
                foreach (TEntity obj in list)
                {
                    string sql = $"insert into {TableName}({GetField(obj)}) values({GetField(obj, "@")});";
                    res += await BaseInsert<int>(sql, obj, transaction);
                }
                transaction.Commit();
            }
            catch (Exception ex)
            {
                transaction.Rollback();
            }
            return res;
        }
        /// <summary>
        /// 批量新增
        /// </summary>
        /// <param name="list"></param>
        /// <param name="fields">新增的字段</param>
        /// <returns></returns>
        public async Task<int> Insert(List<TEntity> list, string[] fields)
        {
            int res = 0;

            IDbTransaction transaction = _conn.BeginTransaction();
            try
            {
                foreach (TEntity obj in list)
                {
                    string sql = $"insert into {TableName}({SqlHelper.SqlJoin(fields)}) values({SqlHelper.SqlValueJoin(fields)})";
                    res += await BaseInsert<int>(sql, obj, transaction);
                }
                transaction.Commit();
            }
            catch (Exception ex)
            {
                transaction.Rollback();
            }
            return res;
        }
        #endregion

        #region 查询
        public async Task<TEntity> Get(int code, CacheModel cacheEntity = null)
        {
            string sql = $"select * from {TableName} where Id=@Id";
            return await BaseGet<TEntity>(sql, new { Id = code }, cacheEntity);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sql"></param>
        /// <param name="param"></param>
        /// <param name="IsCache">是否读取缓存</param>
        /// <param name="CacheTime">缓存时间，0表示不缓存</param>
        /// <returns></returns>
        public async Task<TEntity> Get(object param, string sqlWhere, string showFields = "*", CacheModel cacheEntity = null)
        {
            string sql = $"select {showFields} from {TableName} where {sqlWhere}";
            return await BaseGet<TEntity>(sql, param, cacheEntity);
        }

        /// <summary>
        /// 通用列表查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sql"></param>
        /// <param name="param"></param>
        /// <param name="cacheEntity"></param>
        /// <returns></returns>
        public async Task<IEnumerable<TEntity>> GetList(CacheModel cacheEntity = null)
        {
            string sql = $"select * from {TableName}";

            return await BaseGetList<TEntity>(sql, null, cacheEntity);
        }

        public async Task<IEnumerable<TEntity>> GetList(object param, string sqlWhere, string orderBy, string showFields = "*", CacheModel cacheEntity = null)
        {
            orderBy = !string.IsNullOrWhiteSpace(orderBy) ? $" order by {orderBy}" : "";
            sqlWhere = !string.IsNullOrWhiteSpace(sqlWhere) ? sqlWhere : "1=1";
            string sql = $"select {showFields} from {TableName} where {sqlWhere} {orderBy} ";

            return await BaseGetList<TEntity>(sql, param, cacheEntity);
        }

        public async Task<IEnumerable<TEntity>> GetTopList(int TopNumber, object param, string sqlWhere, string orderBy, string showFields = "*", CacheModel cacheEntity = null)
        {
            orderBy = !string.IsNullOrWhiteSpace(orderBy) ? $" order by {orderBy}" : "";
            sqlWhere = !string.IsNullOrWhiteSpace(sqlWhere) ? sqlWhere : "1=1";
            string sql = $"select top({TopNumber}) {showFields} from {TableName} where {sqlWhere} {orderBy}";
            return await BaseGetList<TEntity>(sql, param, cacheEntity);
        }
        /// <summary>
        /// 分页查询
        /// </summary>
        /// <param name="page">当前页</param>
        /// <param name="pageSize">每页大小</param>
        /// <param name="param">条件参数</param>
        /// <param name="sqlWhere">条件</param>
        /// <param name="orderBy">排序</param>
        /// <param name="showFields">显示字段</param>
        /// <param name="cacheEntity">缓存</param>
        /// <returns></returns>
        public async Task<IEnumerable<TEntity>> GetPage(int page, int pageSize, object param, string sqlWhere, string orderBy, string showFields = "*", CacheModel cacheEntity = null)
        {
            string sql = $"select {showFields} from {TableName} where 1 = 1 {sqlWhere} {orderBy} limit {(page == 0 ? 0 : ((page - 1) * pageSize))},{pageSize}";
            return await BaseGetList<TEntity>(sql, param, cacheEntity);
        }
        #endregion

        #region 其它
        /// <summary>
        /// 检测是否存在
        /// </summary>
        /// <param name="param">参数实体</param>
        /// <param name="sqlWhere">where条件，参数化写法，值放param里传</param>
        /// <returns>true or false</returns>
        public async Task<bool> IsExist(object param, string sqlWhere)
        {
            string sql = $"select count(1) from {TableName} where {sqlWhere}";
            return await BaseQuery(sql, param) > 0;
        }
        /// <summary>
        /// 查询总数量
        /// </summary>
        /// <param name="param">参数实体</param>
        /// <param name="sqlWhere">where条件，参数化写法，值放param里传</param>
        /// <returns>数量</returns>
        public async Task<int> GetCount(object param, string sqlWhere)
        {
            string sql = $"select count(1) from {TableName} where 1 = 1 {sqlWhere}";
            return await BaseQuery(sql, param);
        }
        #endregion

        #region 公用方法
        /// <summary>
        /// 获取对象字段
        /// </summary>
        /// <param name="obj">目标对象</param>
        /// <param name="prefix">字符串前缀(@)</param>
        /// <returns></returns>
        public string GetField(object obj, string prefix = "")
        {
            string str = "";
            Type Ts = obj.GetType();
            PropertyInfo[] Fields = Ts.GetProperties();
            foreach (PropertyInfo field in Fields)
            {
                //主键
                if (field.Name == "Id")
                    continue;
                str = $"{str}{prefix}{field.Name},";
            }
            return str.TrimEnd(',');
        }
        #endregion
    }
}
